﻿using System;
using System.Collections.Generic;
using System.Linq;
using QuantumNet.Base.Interfaces;

namespace QuantumNet.Base
{
    public class DoubleArithmetic:IReal<double>
    {
        #region Implementation of IArithmetic<double>

        public double Add(double left, double right)
        {
            return left + right;
        }

        public double Subtract(double left, double right)
        {
            return left - right;
        }

        public double Multiply(double left, double right)
        {
            return left*right;
        }

        public double Divide(double numerator, double denominator)
        {
            return numerator/denominator;
        }

        public double Modulo(double left, double right)
        {
            return left%right;
        }

        public double Increment(double value)
        {
            return value+1;
        }

        public double Decrement(double value)
        {
            return value-1;
        }

        public double Inverse(double value)
        {
            return 1d/value;
        }

        public double Zero()
        {
            return 0.0;
        }

        public double One()
        {
            return 1.0;
        }

        public double Abs(double value)
        {
            return Math.Abs(value);
        }

        public double Sqr(double value)
        {
            return value*value;
        }

        public double E
        {
            get { return Math.E; }
        }

        public double Pi { get { return Math.PI; }
        }

        public double MeisselMertens
        {
            get { return 0.261497212847642; }
        }

        public double Oméga
        {
            get { return 0.567143290409783; }
        }

        public double EulerMascheroni
        {
            get { return 0.57721566490153; }
        }

        public double GolombDickman
        {
            get { return  0.6243299885;}
        }

        public double Cahen
        {
            get { return 0.64341054628833; }
        }

        public double PrimeJumeaux
        {
            get { return 0.66016181584686; }
        }

        public double Robbins
        {
            get { return 0.661707182267; }
        }

        public double EmbreeTrefethen
        {
            get { return 0.70258; }
        }

        public double Gauss
        {
            get { return 0.834626842; }
        }

        public double Laplace
        {
            get { return 0.6627434193; }
        }

        public double BrunQuadruplet
        {
            get { return 0.8705883800; }
        }

        public double Catalan
        {
            get { return 0.91596559417721; }
        }

        public double HafnerSarnarkMcCurley
        {
            get { return 0.3532363719; }
        }

        public double Bernstein
        {
            get { return 0.2801694990; }
        }

        public double GaussKurminWirsing
        {
            get { return 0.3036630029; }
        }

        public double AlladiGrinstead
        {
            get { return 0.8093940205; }
        }

        public double Legendre
        {
            get { return 1.08366; }
        }

        public double Viswanath
        {
            get { return 1.0986858055; }
        }

        public double KhinchinLevy
        {
            get { return 1.1865691104; }
        }

        public double Apery
        {
            get { return 1.20205690315959; }
        }

        public double Lengyel
        {
            get { return 1.0986858055; }
        }

        public double Mills
        {
            get { return 1.30637788386308; }
        }

        public double GlaisherKinkelin
        {
            get { return 1.28242712; }
        }

        public double Plastic
        {
            get { return 1.324717957244746; }
        }

        public double RamanujanSoldner
        {
            get { return 1.451369234883381; }
        }

        public double Backhouse
        {
            get { return 1.45607494858269; }
        }

        public double Porter
        {
            get { return 1.4670780794; }
        }

        public double LiebSquareIce
        {
            get { return 1.5396007178; }
        }

        public double ErdősBorwein
        {
            get { return 1.606695152415291763; }
        }

        public double GoldenRatio
        {
            get { return 1.618033988749894; }
        }

        public double Niven
        {
            get { return 1.70521114010537; }
        }

        public double PrimeBrunJumeaux
        {
            get { return 1.9021605823; }
        }

        public double FeigenbaumSeconde
        {
            get { return 2.502907875095892; }
        }

        public double Sierpinski
        {
            get { return 2.5849817596; }
        }

        public double Lemniscate
        {
            get { return 2.6220575543; }
        }

        public double Khinchin
        {
            get { return 2.685452001065306; }
        }

        public double FransénRobinson
        {
            get { return 2.807770242028519; }
        }

        public double FibonacciInverse
        {
            get { return 3.359885666243177; }
        }

        public double FeigenbaumPremiere
        {
            get { return 4.669201609102990; }
        }

        public double Pow(double a, double b)
        {
            return Math.Pow(a, b);
        }

        public double Log(double value)
        {
            return Math.Log10(value);
        }

        public double Ln(double value)
        {
            return Math.Log(value);
        }

        public double Sum(List<double> list)
        {
            return list.Sum();
        }

        public double Prod(List<double> list)
        {
            return list.Aggregate<double, double>(1, (current, d) => current*d);
        }

        public double Sqrt(double value)
        {
            return Math.Sqrt(value);
        }

        public double SqrtN(double value, double radicande)
        {
            if (radicande < 0)
            {
                var temps = Math.Pow(Math.Abs(radicande), (1 / value));
                return -temps;
            }
            return Math.Pow(radicande, (1 / value));
        }

        public double Epsilon { get { return 0.0000000001; }}

        public bool IsLess(double left, double right)
        {
            return left < right;
        }

        public bool IsEqual(double left, double right)
        {
            if (left == 0 && right == 0)
                return true;
            return Math.Abs(left - right) < Epsilon ;
        }

        public bool IsGreater(double left, double right)
        {
            return left > right;
        }

        public bool IsLessEqual(double left, double right)
        {
            return left <= right;
        }

        public bool IsGreatEqual(double left, double right)
        {
            return left >= right;
        }

        public bool IsNotEqual(double left, double right)
        {
            return Math.Abs(left - right) > Epsilon;
        }

       

        #endregion

        #region Implementation of ITrigonometry<double>

        public double Sin(double value)
        {
            return Math.Sin(value);
        }

        public double Cos(double value)
        {
            return Math.Cos(value);
        }

        public double Tan(double value)
        {
            return Math.Tan(value);
        }

        public double Asin(double value)
        {
            return Math.Asin(value);
        }

        public double Acos(double value)
        {
            return Math.Acos(value);
        }

        public double Atan(double value)
        {
            return Math.Atan(value);
        }

        public double Sinh(double value)
        {
            return Math.Sinh(value);
        }

        public double Cosh(double value)
        {
            return Math.Cosh(value);
        }

        public double Tanh(double value)
        {
            return Math.Tanh(value);
        }

        public double Asinh(double value)
        {
            return Math.Log(value + Math.Pow((Math.Pow(value, 2) - 1), 0.5));
        }

        public double Acosh(double value)
        {
            return Math.Log(value + Math.Pow((Math.Pow(value, 2) - 1), 0.5));
        }

        public double Atanh(double value)
        {
            return 0.5 * Math.Log((1 + value) / (1 - value));
        }

        #endregion

        #region Implementation of IReal<double>

        public double Negate(double value)
        {
            return -value;
        }

        #endregion

        #region Implementation of ILimit<double>

        public double Maximum
        {
            get { return double.PositiveInfinity; }
        }

        public double Minimum
        {
            get { return double.NegativeInfinity; }
        }

        #endregion
    }
}
